#pragma once

#include <iostream>
#include <memory>
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Log.hpp"
static const int revs_num = 128;

class Reactor
{
private:
    bool IsConnectionExitsHelper(int sockfd)
    {
        auto ret = _connections.find(sockfd);
        if (ret == _connections.end())
            return false;
        return true;
    }
    bool IsConnectionExits(std::shared_ptr<Connection> &conn)
    {
        return IsConnectionExitsHelper(conn->GetSockFd());
    }
    bool IsConnectionExits(int sockfd)
    {
        return IsConnectionExitsHelper(sockfd);
    }
    bool IsConnectionEmpty()
    {
        return _connections.empty();
    }

    int LoopOnce(int timeout)
    {
        return _epoller_ptr->WaitEvents(_revs, revs_num, timeout);
    }
    void Dispatcher(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;

            // 1. 把epoll的异常全部都转化为IO异常
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);

            if (revents & EPOLLIN)
            {
                // 不需要区分异常，读出错了，统一进行异常处理
                // 这里就不需要再去区分是listensocket还是普通socket了
                if (IsConnectionExits(sockfd)) // 注意加这一句代码：可能会有异常处理，处理的时候导致移除了connection
                    _connections[sockfd]->Recver();
            }
            if (revents & EPOLLOUT)
            {
                if (IsConnectionExits(sockfd))
                    _connections[sockfd]->Sender();
            }
        }
    }

public:
    Reactor() : _epoller_ptr(std::make_unique<Epoller>()), _isruning(false)
    {
    }
    void Loop()
    {
        if (IsConnectionEmpty())
            return;
        _isruning = true;
        while (true)
        {
            Print();
            int timeout = -1;
            int n = LoopOnce(timeout);
            Dispatcher(n);
        }
        _isruning = false;
    }
    void StopServer()
    {
        _isruning = false;
    }
    // 该接口要把所有的新链接都添加到_connections，写到epoll内核中
    void AddConnection(std::shared_ptr<Connection> &conn)
    {
        // 0.不要重复添加
        if (IsConnectionExits(conn))
        {
            LOG(LogLevel::WARING) << "conn is exists: " << conn->GetSockFd();
            return;
        }
        // 1.把conn对应的fd和它的事件写透到内核里
        uint32_t events = conn->GetEvent();
        int sockfd = conn->GetSockFd();
        _epoller_ptr->AddEvent(sockfd, events);

        // 2.设置回指指针
        conn->SetOwner(this);

        // 3.把具体的connection插入到_connections
        _connections[sockfd] = conn;
    }
    void EnableReadWrite(int sockfd, bool enableread, bool enablewrite)
    {
        if(!IsConnectionExits(sockfd))
        {
            LOG(LogLevel::WARING) << "conn is exists: " << sockfd;
            return;
        }
        //1.修改当前的Connection对应的关心
        uint32_t events = (EPOLLET | (enableread ? EPOLLIN : 0) | (enablewrite ? EPOLLOUT : 0));
        //2.写透到内核，修改epoll内核的事件
        _connections[sockfd]->SetEvent(events);
        _epoller_ptr->ModEvent(sockfd, events);
    }
    void DeleteConnection(int sockfd)
    {
        //1.先从epoll移除，sockfd必须是合法的
        _epoller_ptr->DelEvent(sockfd);
        //2.从_connections中移除
        _connections.erase(sockfd);
        //3.关闭不要的sockfd
        close(sockfd);
        LOG(LogLevel::INFO)  << "client quit: " << sockfd;
    }
    void Print()
    {
        std::cout<<"当前的Reactor正在管理的fd有: " << std::endl;
        for (auto &conn : _connections)
        {
            std::cout << "sockfd: " << conn.first << std::endl;
        }
        std::cout << std::endl;
    }
    ~Reactor()
    {
    }

private:
    // 1. epoll模型
    std::unique_ptr<Epoller> _epoller_ptr;
    // 不需要了，listener继承了Connection，listensocket的accept就是普通套接字的recv，直接用connect包装
    //  //获取新链接的listen模块
    //  std::shared_ptr<Listener> _listener_ptr;
    // 2. 管理connect，其实就是管理所有的fd
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    // 3.是否启动
    bool _isruning;
    // 4.就绪的所有事件
    struct epoll_event _revs[revs_num];
};